home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / VideoFolder 1.0a / Source / MoreFiles 1.4.1 / FSpCompat.c < prev    next >
Text File  |  1996-01-06  |  26KB  |  911 lines

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    FSSpec compatibility functions.
  5. **
  6. **    by Jim Luther, Apple Developer Technical Support Emeritus
  7. **
  8. **    File:        FSpCompat.c
  9. **
  10. **    Copyright © 1992-1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. /*
  23. **    If building application 68K code, set GENERATENODATA to 0 for faster code.
  24. **    If building stand-alone 68K code, set GENERATENODATA to 1 so globals
  25. **        (static variables) are not used.
  26. */
  27. #define    GENERATENODATA 0
  28.  
  29. #include <Types.h>
  30. #include <Errors.h>
  31. #include <LowMem.h>
  32. #include <Gestalt.h>
  33. #include <Resources.h>
  34. #include <Script.h>
  35. #include "MoreFilesExtras.h"
  36. #include "FSpCompat.h"
  37.  
  38. /*****************************************************************************/
  39.  
  40. /* local constants */
  41.  
  42. enum {
  43.     gestaltBugFixAttrsTwo                    = 'bugy',
  44.     gestaltFSpExchangeFilesCompatibilityFix    = 26,
  45.     gestaltBugFixAttrsThree                    = 'bugx',
  46.     gestaltFSpCreateScriptSupportFix        = 1
  47. };
  48.  
  49. /*****************************************************************************/
  50.  
  51. /* static prototypes */
  52.  
  53.  
  54. #if !SystemSevenOrLater
  55. static    Boolean    FSHasFSSpecCalls(void);
  56.  
  57. static    Boolean    QTHasFSSpecCalls(void);
  58. #endif    /* !SystemSevenOrLater */
  59.  
  60. #if !SystemSevenFiveOrLater
  61. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void);
  62. #endif    /* !SystemSevenFiveOrLater */
  63.  
  64. static    Boolean    HasFSpCreateScriptSupportFix(void);
  65.  
  66. #if !SystemSevenFiveOrLater
  67. static    OSErr    GenerateUniqueName(short volume,
  68.                                    long *startSeed,
  69.                                    long dir1,
  70.                                    long dir2,
  71.                                    StringPtr uniqueName);
  72. #endif    /* !SystemSevenFiveOrLater */
  73.  
  74. /*****************************************************************************/
  75.  
  76. /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
  77.  
  78. #if !SystemSevenOrLater
  79. static    Boolean    FSHasFSSpecCalls(void)
  80. {
  81.     long            response;
  82. #if !GENERATENODATA
  83.     static Boolean    tested = false;
  84.     static Boolean    result = false;
  85. #else
  86.     Boolean    result = false;
  87. #endif
  88.     
  89. #if !GENERATENODATA
  90.     if ( !tested )
  91.     {
  92.         tested = true;
  93. #endif
  94.         if ( Gestalt(gestaltFSAttr, &response) == noErr )
  95.         {
  96.             result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
  97.         }
  98. #if !GENERATENODATA
  99.     }
  100. #endif
  101.     return ( result );
  102. }
  103. #endif    /* !SystemSevenOrLater */
  104.  
  105. /*****************************************************************************/
  106.  
  107. /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
  108. /* except for FSpExchangeFiles. */
  109.  
  110. #if !SystemSevenOrLater
  111. static    Boolean    QTHasFSSpecCalls(void)
  112. {
  113.     long            response;
  114. #if !GENERATENODATA
  115.     static Boolean    tested = false;
  116.     static Boolean    result = false;
  117. #else
  118.     Boolean    result = false;
  119. #endif
  120.     
  121. #if !GENERATENODATA
  122.     if ( !tested )
  123.     {
  124.         tested = true;
  125. #endif
  126.         result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
  127. #if !GENERATENODATA
  128.     }
  129. #endif
  130.     return ( result );
  131. }
  132. #endif    /* !SystemSevenOrLater */
  133.  
  134. /*****************************************************************************/
  135.  
  136. /* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
  137. /* compatibility code has been fixed in system software. */
  138. /* This was fixed by System Update 3.0, so if SystemSevenFiveOrLater */
  139. /* is true, then we know the fix is in. */
  140.  
  141. #if !SystemSevenFiveOrLater
  142. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void)
  143. {
  144.     long            response;
  145. #if !GENERATENODATA
  146.     static Boolean    tested = false;
  147.     static Boolean    result = false;
  148. #else    /* !GENERATENODATA */
  149.     Boolean    result = false;
  150. #endif    /* !GENERATENODATA */
  151.     
  152. #if !GENERATENODATA
  153.     if ( !tested )
  154.     {
  155.         tested = true;
  156. #endif    /* !GENERATENODATA */
  157.         if ( Gestalt(gestaltBugFixAttrsTwo, &response) == noErr )
  158.         {
  159.             result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
  160.         }
  161. #if !GENERATENODATA
  162.     }
  163. #endif    /* !GENERATENODATA */
  164.     return ( result );
  165. }
  166. #endif    /* !SystemSevenFiveOrLater */
  167.  
  168. /*****************************************************************************/
  169.  
  170. /* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
  171. /* FSpCreateResFile have been fixed in system software to correctly set */
  172. /* the scriptCode in the volume's catalog. */
  173. /* This was fixed by System 7.5 Update 1.0 */
  174.  
  175. static    Boolean    HasFSpCreateScriptSupportFix(void)
  176. {
  177.     long            response;
  178. #if !GENERATENODATA
  179.     static Boolean    tested = false;
  180.     static Boolean    result = false;
  181. #else
  182.     Boolean    result = false;
  183. #endif    /* !GENERATENODATA */
  184.     
  185. #if !GENERATENODATA
  186.     if ( !tested )
  187.     {
  188.         tested = true;
  189. #endif    /* !GENERATENODATA */
  190.         if ( Gestalt(gestaltBugFixAttrsThree, &response) == noErr )
  191.         {
  192.             result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
  193.         }
  194. #if !GENERATENODATA
  195.     }
  196. #endif    /* !GENERATENODATA */
  197.     return ( result );
  198. }
  199.  
  200. /*****************************************************************************/
  201.  
  202. /*
  203. **    File Manager FSp calls
  204. */
  205.  
  206. /*****************************************************************************/
  207.  
  208. pascal    OSErr    FSMakeFSSpecCompat(short vRefNum,
  209.                                    long dirID,
  210.                                    ConstStr255Param fileName,
  211.                                    FSSpecPtr spec)
  212. {
  213.     OSErr    result;
  214.     
  215. #if !SystemSevenOrLater
  216.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  217. #endif    /* !SystemSevenOrLater */
  218.     {
  219.         /* Let the file system create the FSSpec if it can since it does the job */
  220.         /* much more efficiently than I can. */
  221.         result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
  222.         /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
  223.         /* returned in the parID field when making an FSSpec to the volume's */
  224.         /* root directory by passing a full pathname in MakeFSSpec's */
  225.         /* fileName parameter. */
  226.         if ( (result == noErr) && (spec->parID == 0) )
  227.             spec->parID = fsRtParID;
  228.     }
  229. #if !SystemSevenOrLater
  230.     else
  231.     {
  232.         Boolean    isDirectory;
  233.         
  234.         result = GetObjectLocation(vRefNum, dirID, (StringPtr)fileName,
  235.                                     &(spec->vRefNum), &(spec->parID), spec->name,
  236.                                     &isDirectory);
  237.     }
  238. #endif    /* !SystemSevenOrLater */
  239.     return ( result );
  240. }
  241.  
  242. /*****************************************************************************/
  243.  
  244. pascal    OSErr    FSpOpenDFCompat(const FSSpec *spec,
  245.                                 char permission,
  246.                                 short *refNum)
  247. {
  248. #if !SystemSevenOrLater
  249.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  250. #endif    /* !SystemSevenOrLater */
  251.     {
  252.         return ( FSpOpenDF(spec, permission, refNum) );
  253.     }
  254. #if !SystemSevenOrLater
  255.     else
  256.     {
  257.         OSErr            result;
  258.         HParamBlockRec    pb;
  259.         
  260.         pb.ioParam.ioVRefNum = spec->vRefNum;
  261.         pb.fileParam.ioDirID = spec->parID;
  262.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  263.         pb.ioParam.ioVersNum = 0;
  264.         pb.ioParam.ioPermssn = permission;
  265.         pb.ioParam.ioMisc = NULL;
  266.         result = PBHOpenSync(&pb);    /* OpenDF not supported by System 6, so use Open */
  267.         *refNum = pb.ioParam.ioRefNum;
  268.         return ( result );
  269.     }
  270. #endif    /* !SystemSevenOrLater */
  271. }
  272.  
  273. /*****************************************************************************/
  274.  
  275. pascal    OSErr    FSpOpenRFCompat(const FSSpec *spec,
  276.                                 char permission,
  277.                                 short *refNum)
  278. {
  279. #if !SystemSevenOrLater
  280.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  281. #endif    /* !SystemSevenOrLater */
  282.     {
  283.         return ( FSpOpenRF(spec, permission, refNum) );
  284.     }
  285. #if !SystemSevenOrLater
  286.     else
  287.     {
  288.         OSErr            result;
  289.         HParamBlockRec    pb;
  290.         
  291.         pb.ioParam.ioVRefNum = spec->vRefNum;
  292.         pb.fileParam.ioDirID = spec->parID;
  293.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  294.         pb.ioParam.ioVersNum = 0;
  295.         pb.ioParam.ioPermssn = permission;
  296.         pb.ioParam.ioMisc = NULL;
  297.         result = PBHOpenRFSync(&pb);
  298.         *refNum = pb.ioParam.ioRefNum;
  299.         return ( result );
  300.     }
  301. #endif    /* !SystemSevenOrLater */
  302. }
  303.  
  304. /*****************************************************************************/
  305.  
  306. pascal    OSErr    FSpCreateCompat(const FSSpec *spec,
  307.                                 OSType creator,
  308.                                 OSType fileType,
  309.                                 ScriptCode scriptTag)
  310. {
  311.     OSErr            result;
  312.     UniversalFMPB    pb;
  313.     
  314.     /* There's no conditional to test for, so this test must be made */
  315.     if ( HasFSpCreateScriptSupportFix() )
  316.     {
  317.         return ( FSpCreate(spec, creator, fileType, scriptTag) );
  318.     }
  319.     /*    If FSpCreate isn't called, this code will be executed */
  320.     pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  321.     pb.hPB.fileParam.ioDirID = spec->parID;
  322.     pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  323.     pb.hPB.fileParam.ioFVersNum = 0;
  324.     result = PBHCreateSync(&(pb.hPB));
  325.     if ( result == noErr )
  326.     {
  327.         /* get info on created item */
  328.         pb.ciPB.hFileInfo.ioFDirIndex = 0;
  329.         result = PBGetCatInfoSync(&(pb.ciPB));
  330.         if ( result == noErr )
  331.         {
  332.             /* Set fdScript in FXInfo */
  333.             /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  334.             /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  335.             /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  336.             pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  337.                                                         ((char)scriptTag | (char)0x80) :
  338.                                                         (smRoman);
  339.             /* Set creator/fileType */
  340.             pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  341.             pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
  342.             /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  343.             pb.ciPB.hFileInfo.ioDirID = spec->parID;
  344.             result = PBSetCatInfoSync(&(pb.ciPB));
  345.         }
  346.     }
  347.     return ( result );
  348. }
  349.  
  350. /*****************************************************************************/
  351.  
  352. pascal    OSErr    FSpDirCreateCompat(const FSSpec *spec,
  353.                                    ScriptCode scriptTag,
  354.                                    long *createdDirID)
  355. {
  356. #if !SystemSevenOrLater
  357.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  358. #endif    /* !SystemSevenOrLater */
  359.     {
  360.         return ( FSpDirCreate(spec, scriptTag, createdDirID) );
  361.     }
  362. #if !SystemSevenOrLater
  363.     else
  364.     {
  365.         OSErr            result;
  366.         UniversalFMPB    pb;
  367.         
  368.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  369.         pb.hPB.fileParam.ioDirID = spec->parID;
  370.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  371.         result = PBDirCreateSync(&(pb.hPB));
  372.         *createdDirID = pb.hPB.fileParam.ioDirID;
  373.         if ( result == noErr )
  374.         {
  375.             /* get info on created item */
  376.             pb.ciPB.dirInfo.ioFDirIndex = 0;
  377.             pb.ciPB.dirInfo.ioDrDirID = spec->parID;
  378.             result = PBGetCatInfoSync(&(pb.ciPB));
  379.             if ( result == noErr )
  380.             {
  381.                 /* Set frScript in DXInfo */
  382.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  383.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  384.                 /* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
  385.                 pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
  386.                                                             ((char)scriptTag | (char)0x80) :
  387.                                                             (smRoman);
  388.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  389.                 pb.ciPB.dirInfo.ioDrDirID = spec->parID;            
  390.                 result = PBSetCatInfoSync(&(pb.ciPB));
  391.             }
  392.         }
  393.         return ( result );
  394.     }
  395. #endif    /* !SystemSevenOrLater */
  396. }
  397.  
  398. /*****************************************************************************/
  399.  
  400. pascal    OSErr    FSpDeleteCompat(const FSSpec *spec)
  401. {
  402. #if !SystemSevenOrLater
  403.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  404. #endif    /* !SystemSevenOrLater */
  405.     {
  406.         return ( FSpDelete(spec) );
  407.     }
  408. #if !SystemSevenOrLater
  409.     else
  410.     {
  411.         HParamBlockRec    pb;
  412.         
  413.         pb.ioParam.ioVRefNum = spec->vRefNum;
  414.         pb.fileParam.ioDirID = spec->parID;
  415.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  416.         pb.ioParam.ioVersNum = 0;
  417.         return ( PBHDeleteSync(&pb) );
  418.     }
  419. #endif    /* !SystemSevenOrLater */
  420. }
  421.  
  422. /*****************************************************************************/
  423.  
  424. pascal    OSErr    FSpGetFInfoCompat(const FSSpec *spec,
  425.                                   FInfo *fndrInfo)
  426. {
  427. #if !SystemSevenOrLater
  428.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  429. #endif    /* !SystemSevenOrLater */
  430.     {
  431.         return ( FSpGetFInfo(spec, fndrInfo) );
  432.     }
  433. #if !SystemSevenOrLater
  434.     else
  435.     {
  436.         OSErr            result;
  437.         HParamBlockRec    pb;
  438.         
  439.         pb.fileParam.ioVRefNum = spec->vRefNum;
  440.         pb.fileParam.ioDirID = spec->parID;
  441.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  442.         pb.fileParam.ioFVersNum = 0;
  443.         pb.fileParam.ioFDirIndex = 0;
  444.         result = PBHGetFInfoSync(&pb);
  445.         *fndrInfo = pb.fileParam.ioFlFndrInfo;
  446.         return ( result );
  447.     }
  448. #endif    /* !SystemSevenOrLater */
  449. }
  450.  
  451. /*****************************************************************************/
  452.  
  453. pascal    OSErr    FSpSetFInfoCompat(const FSSpec *spec,
  454.                                   const FInfo *fndrInfo)
  455. {
  456. #if !SystemSevenOrLater
  457.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  458. #endif    /* !SystemSevenOrLater */
  459.     {
  460.         return ( FSpSetFInfo(spec, fndrInfo) );
  461.     }
  462. #if !SystemSevenOrLater
  463.     else
  464.     {
  465.         OSErr            result;
  466.         HParamBlockRec    pb;
  467.         
  468.         pb.fileParam.ioVRefNum = spec->vRefNum;
  469.         pb.fileParam.ioDirID = spec->parID;
  470.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  471.         pb.fileParam.ioFVersNum = 0;
  472.         pb.fileParam.ioFDirIndex = 0;
  473.         result = PBHGetFInfoSync(&pb);
  474.         if ( result == noErr )
  475.         {
  476.             pb.fileParam.ioFlFndrInfo = *fndrInfo;
  477.             pb.fileParam.ioDirID = spec->parID;
  478.             result = PBHSetFInfoSync(&pb);
  479.         }
  480.         return ( result );
  481.     }
  482. #endif    /* !SystemSevenOrLater */
  483. }
  484.  
  485. /*****************************************************************************/
  486.  
  487. pascal    OSErr    FSpSetFLockCompat(const FSSpec *spec)
  488. {
  489. #if !SystemSevenOrLater
  490.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  491. #endif    /* !SystemSevenOrLater */
  492.     {
  493.         return ( FSpSetFLock(spec) );
  494.     }
  495. #if !SystemSevenOrLater
  496.     else
  497.     {
  498.         HParamBlockRec    pb;
  499.         
  500.         pb.fileParam.ioVRefNum = spec->vRefNum;
  501.         pb.fileParam.ioDirID = spec->parID;
  502.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  503.         pb.fileParam.ioFVersNum = 0;
  504.         return ( PBHSetFLockSync(&pb) );
  505.     }
  506. #endif    /* !SystemSevenOrLater */
  507. }
  508.  
  509. /*****************************************************************************/
  510.  
  511. pascal    OSErr    FSpRstFLockCompat(const FSSpec *spec)
  512. {
  513. #if !SystemSevenOrLater
  514.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  515. #endif    /* !SystemSevenOrLater */
  516.     {
  517.         return ( FSpRstFLock(spec) );
  518.     }
  519. #if !SystemSevenOrLater
  520.     else
  521.     {
  522.         HParamBlockRec    pb;
  523.         
  524.         pb.fileParam.ioVRefNum = spec->vRefNum;
  525.         pb.fileParam.ioDirID = spec->parID;
  526.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  527.         pb.fileParam.ioFVersNum = 0;
  528.         return ( PBHRstFLockSync(&pb) );
  529.     }
  530. #endif    /* !SystemSevenOrLater */
  531. }
  532.  
  533. /*****************************************************************************/
  534.  
  535. pascal    OSErr    FSpRenameCompat(const FSSpec *spec,
  536.                                 ConstStr255Param newName)
  537. {
  538. #if !SystemSevenOrLater
  539.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  540. #endif    /* !SystemSevenOrLater */
  541.     {
  542.         return ( FSpRename(spec, newName) );
  543.     }
  544. #if !SystemSevenOrLater
  545.     else
  546.     {
  547.         HParamBlockRec    pb;
  548.         
  549.         pb.ioParam.ioVRefNum = spec->vRefNum;
  550.         pb.fileParam.ioDirID = spec->parID;
  551.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  552.         pb.ioParam.ioVersNum = 0;
  553.         pb.ioParam.ioMisc = (Ptr) newName;
  554.         return ( PBHRenameSync(&pb) );
  555.     }
  556. #endif    /* !SystemSevenOrLater */
  557. }
  558.  
  559. /*****************************************************************************/
  560.  
  561. pascal    OSErr    FSpCatMoveCompat(const FSSpec *source,
  562.                                  const FSSpec *dest)
  563. {
  564. #if !SystemSevenOrLater
  565.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  566. #endif    /* !SystemSevenOrLater */
  567.     {
  568.         return ( FSpCatMove(source, dest) );
  569.     }
  570. #if !SystemSevenOrLater
  571.     else
  572.     {
  573.         CMovePBRec    pb;
  574.         
  575.         /* source and destination volume must be the same */
  576.         if ( source->vRefNum != dest->vRefNum )
  577.             return ( paramErr );
  578.         
  579.         pb.ioNamePtr = (StringPtr) &(source->name);
  580.         pb.ioVRefNum = source->vRefNum;
  581.         pb.ioDirID = source->parID;
  582.         pb.ioNewDirID = dest->parID;
  583.         pb.ioNewName = (StringPtr) &(dest->name);
  584.         return ( PBCatMoveSync(&pb) );
  585.     }
  586. #endif    /* !SystemSevenOrLater */
  587. }
  588.  
  589. /*****************************************************************************/
  590.  
  591. /* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
  592. /* on the specified volume. Ripped off from Feldman's code. */
  593.  
  594. #if !SystemSevenFiveOrLater
  595. static    OSErr    GenerateUniqueName(short volume,
  596.                                    long *startSeed,
  597.                                    long dir1,
  598.                                    long dir2,
  599.                                    StringPtr uniqueName)
  600. {
  601.     OSErr            error = noErr;
  602.     long            i;
  603.     CInfoPBRec        cinfo;
  604.     unsigned char    hexStr[16];
  605.     
  606.     for ( i = 0; i < 16; ++i )
  607.     {
  608.         if ( i < 10 )
  609.             hexStr[i] = 0x30 + i;
  610.         else
  611.             hexStr[i] = 0x37 + i;
  612.     }
  613.     
  614.     cinfo.hFileInfo.ioVRefNum = volume;
  615.     cinfo.hFileInfo.ioFDirIndex = 0;
  616.     cinfo.hFileInfo.ioNamePtr = uniqueName;
  617.  
  618.     while ( error != fnfErr )
  619.     {
  620.         (*startSeed)++;        
  621.         cinfo.hFileInfo.ioNamePtr[0] = 8;
  622.         for ( i = 1; i <= 8; i++ )
  623.         {
  624.             cinfo.hFileInfo.ioNamePtr[i] = hexStr[((*startSeed >> ((8-i)*4)) & 0xf)];
  625.         }
  626.         cinfo.hFileInfo.ioDirID = dir1;
  627.         error = fnfErr;
  628.         for ( i = 1; i <= 2; i++ )
  629.         {
  630.             error = error & PBGetCatInfoSync(&cinfo);
  631.             cinfo.hFileInfo.ioDirID = dir2;
  632.             if ( (error != fnfErr) && (error != noErr) )
  633.                 return ( error );
  634.         }
  635.     }
  636.     return ( noErr );
  637. }
  638. #endif    /* !SystemSevenFiveOrLater */
  639.  
  640. /*****************************************************************************/
  641.  
  642. pascal    OSErr    FSpExchangeFilesCompat(const FSSpec *source,
  643.                                        const FSSpec *dest)
  644. {
  645. #if !SystemSevenOrLater
  646.     if ( FSHasFSSpecCalls() )
  647. #endif    /* !SystemSevenOrLater */
  648.     {
  649. #if !SystemSevenFiveOrLater
  650.         if ( HasFSpExchangeFilesCompatibilityFix() )
  651. #endif    /* !SystemSevenFiveOrLater */
  652.         {
  653.             return ( FSpExchangeFiles(source, dest) );
  654.         }
  655.     }
  656. #if !SystemSevenFiveOrLater
  657.     /*    If FSpExchangeFiles isn't called, this code will be executed */
  658.     {
  659.         HParamBlockRec            pb;
  660.         CInfoPBRec                catInfoSource, catInfoDest;
  661.         OSErr                    result, result2;
  662.         Str31                    unique1, unique2;
  663.         StringPtr                unique1Ptr, unique2Ptr, swapola;
  664.         GetVolParmsInfoBuffer    volInfo;
  665.         long                    theSeed, temp;
  666.         
  667.         /* Make sure the source and destination are on the same volume */
  668.         if ( source->vRefNum != dest->vRefNum )
  669.         {
  670.             result = paramErr;
  671.             goto errorExit3;
  672.         }
  673.         
  674.         /* Try PBExchangeFiles first since it preserves the file ID reference */
  675.         pb.fidParam.ioNamePtr = (StringPtr) &(source->name);
  676.         pb.fidParam.ioVRefNum = source->vRefNum;
  677.         pb.fidParam.ioDestNamePtr = (StringPtr) &(dest->name);
  678.         pb.fidParam.ioDestDirID = dest->parID;
  679.         pb.fidParam.ioSrcDirID = source->parID;
  680.     
  681.         result = PBExchangeFilesSync(&pb);
  682.     
  683.         /* Note: The compatibility case won't work for files with *Btree control blocks. */
  684.         /* Right now the only *Btree files are created by the system. */
  685.         if ( result != noErr )
  686.         {
  687.             pb.ioParam.ioNamePtr = NULL;
  688.             pb.ioParam.ioBuffer = (Ptr) &volInfo;
  689.             pb.ioParam.ioReqCount = sizeof(volInfo);
  690.             result2 = PBHGetVolParmsSync(&pb);
  691.             
  692.             /* continue if volume has no fileID support (or no GetVolParms support) */
  693.             if ( (result2 == noErr) && hasFileIDs(volInfo) )
  694.                 goto errorExit3;
  695.     
  696.             /* Get the catalog information for each file */
  697.             /* and make sure both files are *really* files */
  698.             catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
  699.             catInfoSource.hFileInfo.ioFDirIndex = 0;
  700.             catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
  701.             catInfoSource.hFileInfo.ioDirID = source->parID;
  702.             catInfoSource.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
  703.             result = PBGetCatInfoSync(&catInfoSource);
  704.             if ( result != noErr )
  705.                 goto errorExit3;
  706.             if ( (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  707.             {
  708.                 result = notAFileErr;
  709.                 goto errorExit3;
  710.             }
  711.             
  712.             catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
  713.             catInfoDest.hFileInfo.ioFDirIndex = 0;
  714.             catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
  715.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  716.             catInfoDest.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
  717.             result = PBGetCatInfoSync(&catInfoDest);
  718.             if ( result != noErr )
  719.                 goto errorExit3;
  720.             if ( (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  721.             {
  722.                 result = notAFileErr;
  723.                 goto errorExit3;
  724.             }
  725.             
  726.             /* generate 2 filenames that are unique in both directories */
  727.             theSeed = 0x64666A6C;    /* a fine unlikely filename */
  728.             unique1Ptr = (StringPtr)&unique1;
  729.             unique2Ptr = (StringPtr)&unique2;
  730.             
  731.             result = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
  732.             if ( result != noErr )
  733.                 goto errorExit3;
  734.     
  735.             GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
  736.             if ( result != noErr )
  737.                 goto errorExit3;
  738.     
  739.             /* rename source to unique1 */
  740.             pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
  741.             pb.ioParam.ioMisc = (Ptr) unique1Ptr;
  742.             pb.ioParam.ioVersNum = 0;
  743.             result = PBHRenameSync(&pb);
  744.             if ( result != noErr )
  745.                 goto errorExit3;
  746.             
  747.             /* rename dest to unique2 */
  748.             pb.ioParam.ioMisc = (Ptr) unique2Ptr;
  749.             pb.ioParam.ioVersNum = 0;
  750.             pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
  751.             pb.fileParam.ioDirID = dest->parID;
  752.             result = PBHRenameSync(&pb);
  753.             if ( result != noErr )
  754.                 goto errorExit2;    /* back out gracefully by renaming unique1 back to source */
  755.                 
  756.             /* If files are not in same directory, swap their locations */
  757.             if ( source->parID != dest->parID )
  758.             {
  759.                 /* move source file to dest directory */
  760.                 pb.copyParam.ioNamePtr = unique1Ptr;
  761.                 pb.copyParam.ioNewName = NULL;
  762.                 pb.copyParam.ioNewDirID = dest->parID;
  763.                 pb.copyParam.ioDirID = source->parID;
  764.                 result = PBCatMoveSync((CMovePBPtr) &pb);
  765.                 if ( result != noErr )
  766.                     goto errorExit1;    /* back out gracefully by renaming both files to original names */
  767.                 
  768.                 /* move dest file to source directory */
  769.                 pb.copyParam.ioNamePtr = unique2Ptr;
  770.                 pb.copyParam.ioNewDirID = source->parID;
  771.                 pb.copyParam.ioDirID = dest->parID;
  772.                 result = PBCatMoveSync((CMovePBPtr) &pb);
  773.                 if ( result != noErr)
  774.                 {
  775.                     /* life is very bad.  We'll at least try to move source back */
  776.                     pb.copyParam.ioNamePtr = unique1Ptr;
  777.                     pb.copyParam.ioNewName = NULL;
  778.                     pb.copyParam.ioNewDirID = source->parID;
  779.                     pb.copyParam.ioDirID = dest->parID;
  780.                     (void) PBCatMoveSync((CMovePBPtr) &pb);    /* ignore errors */
  781.                     goto errorExit1;    /* back out gracefully by renaming both files to original names */
  782.                 }
  783.             }
  784.             
  785.             /* Make unique1Ptr point to file in source->parID */
  786.             /* and unique2Ptr point to file in dest->parID */
  787.             /* This lets us fall through to the rename code below */
  788.             swapola = unique1Ptr;
  789.             unique1Ptr = unique2Ptr;
  790.             unique2Ptr = swapola;
  791.     
  792.             /* At this point, the files are in their new locations (if they were moved) */
  793.             /* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
  794.             /* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
  795.             /* Need to swap attributes except mod date and swap names */
  796.     
  797.             /* swap the catalog info by re-aiming the CInfoPB's */
  798.             catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
  799.             catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
  800.             
  801.             catInfoSource.hFileInfo.ioDirID = source->parID;
  802.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  803.             
  804.             /* Swap the original mod dates with each file */
  805.             temp = catInfoSource.hFileInfo.ioFlMdDat;
  806.             catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
  807.             catInfoDest.hFileInfo.ioFlMdDat = temp;
  808.             
  809.             /* Here's the swap (ignore errors) */
  810.             (void) PBSetCatInfoSync(&catInfoSource); 
  811.             (void) PBSetCatInfoSync(&catInfoDest);
  812.             
  813.             /* rename unique2 back to dest */
  814. errorExit1:
  815.             pb.ioParam.ioMisc = (Ptr) &(dest->name);
  816.             pb.ioParam.ioVersNum = 0;
  817.             pb.fileParam.ioNamePtr = unique2Ptr;
  818.             pb.fileParam.ioDirID = dest->parID;
  819.             (void) PBHRenameSync(&pb);    /* ignore errors */
  820.     
  821.             /* rename unique1 back to source */
  822. errorExit2:
  823.             pb.ioParam.ioMisc = (Ptr) &(source->name);
  824.             pb.ioParam.ioVersNum = 0;
  825.             pb.fileParam.ioNamePtr = unique1Ptr;
  826.             pb.fileParam.ioDirID = source->parID;
  827.             (void) PBHRenameSync(&pb); /* ignore errors */
  828.         }
  829. errorExit3: { /* null statement */ }
  830.         return ( result );
  831.     }
  832. #endif    /* !SystemSevenFiveOrLater */
  833. }
  834.  
  835. /*****************************************************************************/
  836.  
  837. /* 
  838. **    Resource Manager FSp calls
  839. */
  840.  
  841. /*****************************************************************************/
  842.  
  843. pascal    short    FSpOpenResFileCompat(const FSSpec *spec,
  844.                                      SignedByte permission)
  845. {
  846. #if !SystemSevenOrLater
  847.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  848. #endif    /* !SystemSevenOrLater */
  849.     {
  850.         return ( FSpOpenResFile(spec, permission) );
  851.     }
  852. #if !SystemSevenOrLater
  853.     else
  854.     {
  855.         return ( HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission) );
  856.     }
  857. #endif    /* !SystemSevenOrLater */
  858. }
  859.  
  860. /*****************************************************************************/
  861.  
  862. pascal    void    FSpCreateResFileCompat(const FSSpec *spec,
  863.                                        OSType creator,
  864.                                        OSType fileType,
  865.                                        ScriptCode scriptTag)
  866. {    
  867.     if ( HasFSpCreateScriptSupportFix() )
  868.     {
  869.         FSpCreateResFile(spec, creator, fileType, scriptTag);
  870.         return;
  871.     }
  872.     /*    If FSpCreateResFile isn't called, this code will be executed */
  873.     {
  874.         OSErr            result;
  875.         CInfoPBRec        pb;
  876.         
  877.         HCreateResFile(spec->vRefNum, spec->parID, spec->name);
  878.         if ( ResError() == noErr )
  879.         {
  880.             /* get info on created item */
  881.             pb.hFileInfo.ioVRefNum = spec->vRefNum;
  882.             pb.hFileInfo.ioDirID = spec->parID;
  883.             pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
  884.             pb.hFileInfo.ioFDirIndex = 0;
  885.             result = PBGetCatInfoSync(&pb);
  886.             if ( result == noErr )
  887.             {
  888.                 /* Set fdScript in FXInfo */
  889.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  890.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  891.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  892.                 pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  893.                                                         ((char)scriptTag | (char)0x80) :
  894.                                                         (smRoman);
  895.                 /* Set creator/fileType */
  896.                 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  897.                 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
  898.                 
  899.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  900.                 pb.hFileInfo.ioDirID = spec->parID;
  901.                 result = PBSetCatInfoSync(&pb);
  902.             }
  903.             /* Set ResErr low memory global to result */
  904.             LMSetResErr(result);
  905.         }
  906.         return;
  907.     }
  908. }
  909.  
  910. /*****************************************************************************/
  911.